using System.Security.Cryptography;
using System.Text;

namespace CoreManager.Common
{
    /// <summary>
    /// 文件操作辅助类
    /// </summary>
    public static class FileHelper
    {
        /// <summary>
        /// 允许上传的图片扩展名
        /// </summary>
        public static readonly string[] ImageExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg" };

        /// <summary>
        /// 允许上传的文档扩展名
        /// </summary>
        public static readonly string[] DocumentExtensions = { ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt" };

        /// <summary>
        /// 允许上传的压缩包扩展名
        /// </summary>
        public static readonly string[] ArchiveExtensions = { ".zip", ".rar", ".7z", ".tar", ".gz" };

        /// <summary>
        /// 允许上传的视频扩展名
        /// </summary>
        public static readonly string[] VideoExtensions = { ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv" };

        /// <summary>
        /// 允许上传的音频扩展名
        /// </summary>
        public static readonly string[] AudioExtensions = { ".mp3", ".wav", ".flac", ".aac", ".ogg" };

        /// <summary>
        /// 获取所有允许的扩展名
        /// </summary>
        public static string[] AllowedExtensions => 
            ImageExtensions
                .Concat(DocumentExtensions)
                .Concat(ArchiveExtensions)
                .Concat(VideoExtensions)
                .Concat(AudioExtensions)
                .ToArray();

        /// <summary>
        /// 验证文件扩展名是否允许
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="allowedExtensions">允许的扩展名列表，为空则使用默认列表</param>
        /// <returns>是否允许</returns>
        public static bool IsAllowedExtension(string fileName, string[]? allowedExtensions = null)
        {
            if (string.IsNullOrWhiteSpace(fileName))
                return false;

            var extension = Path.GetExtension(fileName).ToLowerInvariant();
            var allowed = allowedExtensions ?? AllowedExtensions;
            
            return allowed.Contains(extension);
        }

        /// <summary>
        /// 判断是否为图片文件
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <returns>是否为图片</returns>
        public static bool IsImage(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName))
                return false;

            var extension = Path.GetExtension(fileName).ToLowerInvariant();
            return ImageExtensions.Contains(extension);
        }

        /// <summary>
        /// 生成唯一文件名
        /// </summary>
        /// <param name="originalFileName">原始文件名</param>
        /// <returns>唯一文件名</returns>
        public static string GenerateUniqueFileName(string originalFileName)
        {
            var extension = Path.GetExtension(originalFileName);
            var timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff");
            var randomString = Guid.NewGuid().ToString("N")[..8];
            return $"{timestamp}_{randomString}{extension}";
        }

        /// <summary>
        /// 计算文件MD5值
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <returns>MD5值</returns>
        public static string CalculateMd5(Stream stream)
        {
            using var md5 = MD5.Create();
            var hash = md5.ComputeHash(stream);
            stream.Position = 0; // 重置流位置
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }

        /// <summary>
        /// 计算文件MD5值
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>MD5值</returns>
        public static string CalculateMd5(string filePath)
        {
            using var stream = File.OpenRead(filePath);
            return CalculateMd5(stream);
        }

        /// <summary>
        /// 格式化文件大小
        /// </summary>
        /// <param name="bytes">字节数</param>
        /// <returns>格式化后的文件大小</returns>
        public static string FormatFileSize(long bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB", "TB" };
            double len = bytes;
            int order = 0;
            
            while (len >= 1024 && order < sizes.Length - 1)
            {
                order++;
                len = len / 1024;
            }

            return $"{len:0.##} {sizes[order]}";
        }

        /// <summary>
        /// 确保目录存在
        /// </summary>
        /// <param name="path">目录路径</param>
        public static void EnsureDirectoryExists(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        /// <summary>
        /// 生成基于日期的子目录路径
        /// </summary>
        /// <param name="businessType">业务类型</param>
        /// <returns>子目录路径</returns>
        public static string GenerateDateBasedPath(string? businessType = null)
        {
            var now = DateTime.Now;
            var pathParts = new List<string>();

            if (!string.IsNullOrWhiteSpace(businessType))
            {
                pathParts.Add(businessType);
            }

            pathParts.Add(now.ToString("yyyy"));
            pathParts.Add(now.ToString("MM"));
            pathParts.Add(now.ToString("dd"));

            return Path.Combine(pathParts.ToArray());
        }

        /// <summary>
        /// 删除文件（安全删除）
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>是否删除成功</returns>
        public static bool SafeDeleteFile(string filePath)
        {
            try
            {
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                    return true;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 清理空目录
        /// </summary>
        /// <param name="directoryPath">目录路径</param>
        public static void CleanupEmptyDirectories(string directoryPath)
        {
            try
            {
                if (!Directory.Exists(directoryPath))
                    return;

                foreach (var directory in Directory.GetDirectories(directoryPath))
                {
                    CleanupEmptyDirectories(directory);
                }

                if (!Directory.EnumerateFileSystemEntries(directoryPath).Any())
                {
                    Directory.Delete(directoryPath);
                }
            }
            catch
            {
                // 忽略清理错误
            }
        }
    }
}


